"""
面向过程：
按照步骤做事，修改需求重写整个的流程

面向对像
把事物堪称对象，每个对象都有
属性名字，年龄
方法：说话，喝药
"""
import time

"""
类相当于是 = 设计图
对象 = 根据这个设计图所创造出来的具体的人
"""

# class Person:   # 人的模板
#     def __init__(self,name):
#         self.name = name    # 实例化属性
#
# P = Person('小明')   #  对象  具体的人

# 继承
# 父类  子类
# 子类会自动的获得 父类的属性和方法
# 优点： 避免的重复写代码

# # 父类
# class Person:
#     def __init__(self,name,age):
#         self.name = name  # 实例化了类的属性
#         self.age = age
#
#     def introduce(self):
#         print(f"我叫是{self.name},今年{self.age}岁")  # 输出  / 功能
# # 子类
# class Student(Person):  # 在括号中写父类的名称
#     pass   # 暂时不添加功能
#
#
# # 使用
# stu = Student  ('小明',18)
# # print(stu)
#
# stu.introduce()   # 使用  子类的名称调用了父类的方法 也是可以输出的



# 派生
# 子类在父类的基础上，增加自己的属性和方法
# 或者重写（覆盖）父类的方法

# 学生 名字、年龄、还要有 分数、还要会学习
# super()


# 父类
# class Person:
#     def __init__(self,name,age):
#         self.name = name
#         self.age = age
#
#     def introduce(self):
#          print(f"我叫是{self.name},今年{self.age}岁")
# # 子类
# class Student(Person):
#     def __init__(self,name,age,score):
#         super().__init__(name,age)    # 复用父类的初始化的逻辑，自动的调用父类的__init__
#         """
#         super的优点
#         1. 自动的查找父类
#         2. 支持多继承
#         3. 代码会更加的灵活
#         """
#         self.score = score   # 新增属性
#
#     # def __init__(self,name,age,score):
#     #     Person.__init__(name,age)     # 手动的写父类的名称  父类改名，这个也要更改，在多继承容易出错
#     #     self.score = score   # 新增属性
#
#
#     # 派生
#     def study(self):
#         print(f"{self.name}正在学习,他的年纪是：{self.age}目标的分数是：{self.score}")
#
# stu = Student('小龙',18,95)
# stu.introduce()   # 输出的是 父类的方法
# stu.study()
#
#


# 属性的查找顺序
"""
当我们想要访问 obj.x,python按照顺序查找

对象  ---- 对象的类 ---- 父类----父类的类--.....--object

"""

# class A:
#     x = 1
# class B(A):
#     pass
# class C(B):
#     pass
#
#
# obj = C()
# print(obj.x)
#
# # 查找路径   C  ---   B   --- A  x =1



# 组合
"""
当两个类是“ 拥有”的关系  不是  “是”  的关系
当一个类的对象作为另一个类的属性

老师的有课程的  （老师是课程）
"""

# class Course:   # 表示的是一门课程
#     def __init__(self,name,price):
#         self.name = name  # 实例化
#         self.price   = price  # 实例化
#     def info(self):
#         print(f"课程：{self.name},价格{self.price}元")  # 实例化一个方法，用于打印课程的价格和信息
#
# class Teacher:
#     def __init__(self,name):
#         self.name = name
#         self.courses = []   # 列表中存储的是 Course 的对象
#     def add_course(self,course):   # course 的对象
#         self.courses.append(course)
#     def show_coursrs(self):    # 展示了老师在这个地方所教的所有课程
#         print(f"{self.name}的课程有")
#         for c in self.courses:
#             c.info()   # 调用的是 Course 的对象方法
#             """
#             体现的是 组合  Teacher类中 拥有多个  course  对象  但是呢，不是继承他们
#             """
# python = Course('python变成课程',999)    # 定义了两个课程以及价格
# math = Course('高数',9999)
#
# teacher = Teacher('龙老师')   # 这个Teacher变成了龙老师
# teacher.add_course(python)
# teacher.add_course(math)
# teacher.show_coursrs()


"""
设计的思路：
封装： 每个类将数据（name,price,course）和操作  info  add_course  封装在一起
组合：Teacher中  将Course类的都西昂和列表来表示老师教的多门课
Course 的 info() 方法被 Teacher 复用，避免重复代码
"""



"""

组合和继承的区别
继承是一个   学生是人类
组合是有一个   老师有一台电脑
"""



# class Computer:
#     def run(self):
#         print('电脑正在运行')
# class Teacher:
#     def __init__(self,name):
#         self.name = name
#         self.computer = Computer()  # 组合:老师有一台电脑
#
#
#
# t = Teacher('白老师')
# t.computer.run()   # 电脑正在运行
#
# # Teacher 类中有一个属性是Computer 类的对象
#
#





# class Phone:
#     def call(self):
#         print("想看雪，请联系我（劳务费200起）")
#
# class Person:
#     def __init__(self,name):
#         self.name = name
#         self.phone = Phone()   # 创建了一个phone的对象，作为 Person 属性保存了下来
#
# p = Person("卖雪的店家")
#
# p.phone.call()
#
#



# 多态

"""
多态是将同一种事物有多种不同的表现的形式
为什么要用到多态
1. 统一调用方式
2. 不需要关系具体的类型，统一使用相同的方法
"""

"""
def 按开关（灯）
    灯.开（）
"""



# class Animal:     # 父类
#     def speak(self):
#         pass
#
# class Dog(Animal):  # 子类
#     def speak(self):  # 重写父类的方法
#         print('汪汪汪')  # 打印
#
# class Cat(Animal):  # 子类
#     def speak(self):  # 重写父类的方法
#         print('喵喵喵')  # 打印
#
# # 统一的调用
#
# def make_sound(animal):  # ()中的参数，随意的起名
#     animal.speak()   # 主要是调用上面的方法
#
#
# d = Dog()   # 接收实例的对象  （）
# c = Cat()   # 接收实例的对象  （）
#
# make_sound(d)
# make_sound(c)



#魔法方法


"""
python中自带的特殊方法，会在特定的操作下进行调用
"""


# class Person:
#     def __init__(self,name):
#         self.name = name
#
#     def __str__(self):   # 使用str魔术方法输出我们的内容
#         """
#         如果没有这个方法，打印的是地址值
#         加了它之后，打印的这个对象会是我们定义的信息
#         也就是小明
#
#         :return:
#         """
#         return self.name
#
# p = Person('小明')
#
# print(p)





  #  __del__: 对象被删除的时执行


# import time
#
# class Foo:
#     def __init__(self,x,filepath,encoding='utf-8'):
#         self.x = x
#         self.f = open(filepath,'rt',encoding=encoding)  # rt是读取
#
#
#     def __del__(self):   # 当对象被销毁时会自动的调用（垃圾回收机制）用于释放内存（关闭文件的操作）
#         print('__del__正在执行')
#         self.f.close()  # 关闭
#
# obj = Foo(1,'a.txt')  # 创建对象，是一个  txt我文件
# print(obj.f.read())   # 后续代码没有的情况，说明这个资源没有使用，则关闭
# time.sleep(3)
# print(obj.f.read())   # 指针应该是在后面，并且返回的是一个空的字符串



# __call__: 让对象像函数一样被调用
#
# class CallMe:
#     def __call__(self):
#         print('我被调用啦')
# obj = CallMe()
# obj()   #  在调用这个对象的时候  ----  自动执行call方法










